<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <img src="https://treasure.qiandaocdn.com/treasure/images/foxjrKIyogL.png?imginfo=w369,h492" alt="">
    <button id="eventbus">发布订阅</button>
    <script>
        // ============================ 对象的不可变性引用 ===========================

        const obj = {
            user: {
                name: '张三',
                age: 18
            }
        }

        const produce = (base, fn) => {
            let copyObj = {}

            let handler = {
                get(target, key, re) {
                    if (key in copyObj) {
                        return Reflect.get(copyObj, key)
                    }

                    if (typeof target[key] === 'object' && target[key] !== null) {
                        return new Proxy(target[key], handler)
                    }

                    return Reflect.get(target, key)
                },
                set(target, prop, value, re) {
                    return Reflect.set(copyObj, prop, value)
                }
            }

            const proxy = new Proxy(base, handler)

            fn(proxy)

            if (Object.keys(copyObj).length === 0) {
                return base
            }

            return JSON.parse(JSON.stringify(proxy))
        }


        const newObj = produce(obj, (proxy) => {
            proxy.user.name = '李四'
            proxy.user.age = 20
        })

        console.log(obj, 'obj')
        console.log(newObj, 'newObj')

        // ============================ 对象的监听 ===========================
        const onWatch = (obj, setBind, getLogger) => {
            let handler = {
                get(target, key, re) {
                    getLogger(key, target[key])
                    return Reflect.get(target, key)
                },
                set(target, key, value, re) {
                    setBind(key, value)
                    return Reflect.set(target, key, value)
                }
            }
            return new Proxy(obj, handler)
        }

        const newPerson = {
            name: '张三',
            age: 18
        }

        const proxyPerson = onWatch(newPerson, (key, value) => {
            console.log(`值${key}被设置为${value}`)
        }, (key, value) => {
            console.log('属性' + key + '被访问', '值为：' + value)
        })

        console.log(proxyPerson.name);


        proxyPerson.name = '李四'

        // ============================ EventBus发布订阅 ===========================

        class EventBus {
            constructor() {
                this.events = {}
            }

            on(event, fn) {
                if (!this.events[event]) {
                    this.events[event] = []
                }
                this.events[event].push(fn)
            }
            emit(event, ...args) {
                if (this.events[event]) {
                    this.events[event].forEach(fn => fn(...args))
                }
            }
            off(event, fn) {
                if (this.events[event]) {
                    this.events[event] = this.events[event].filter(item => item !== fn)
                }
            }
            once(event, fn) {
                const callback = (...args) => {
                    fn(...args)
                    this.off(event, callback)
                }
                this.on(event, callback)
            }

        }

        const eventBus = new EventBus()
        eventBus.on('test', (...args) => {
            console.log(args)
        })

        // 防抖
        const debounce = (fn, delay) => {
            let timer = null;
            return function (...args) {
                if (timer) clearTimeout(timer);
                timer = setTimeout(() => {
                    fn.apply(this, args);
                }, delay);
            };
        }
        // 防抖带立即执行
        const debounceImmediate = (fn, delay, immediate = true) => {
            let timer = null;
            return function (...args) {
                if (timer) clearTimeout(timer);
                if (immediate) {
                    const callNow = !timer;
                    setTimeout(() => {
                        timer = null;
                    }, delay);
                    if (callNow) fn.apply(this, args);
                } else {
                    timer = setTimeout(() => {
                        fn.apply(this, args);
                    }, delay);
                }
            }
        }

        // 节流
        const throttle = (fn, delay) => {
            let timer = null;
            return function (...args) {
                if (timer) return;
                timer = setTimeout(() => {
                    fn.apply(this, args);
                    timer = null;
                }, delay);
            };
        }
        // 节流带立即执行
        const throttleImmediate = (fn, delay, immediate = true) => {
            let timer = null;
            return function (...args) {
                if (timer) return;
                if (immediate) {
                    const callNow = !timer;
                    timer = setTimeout(() => {
                        timer = null;
                    }, delay);
                    if (callNow) fn.apply(this, args);
                } else {
                    timer = setTimeout(() => {
                        fn.apply(this, args);
                        timer = null;
                    }, delay);
                }
            }
        }

        document.querySelector('#eventbus').addEventListener('click', throttleImmediate(() => {
            eventBus.emit('test', 1, 2, 3)
        }, 1000))


        // 浅拷贝 
        // 对象复制, 结构, for in for of处理 Object.assign Object.create {...结构展开}

        // 深拷贝
        const deepClone = (obj, map = new WeakMap()) => {
            if (typeof obj !== 'object' || obj === null) return obj
            if (obj instanceof Date) return new Date(obj)
            if (obj instanceof RegExp) return new RegExp(obj)
            if (map.has(obj)) return map.get(obj)
            let cloneObj = Array.isArray(obj) ? [] : {}
            map.set(obj, cloneObj)
            for (let key in obj) {
                if (obj.hasOwnProperty(key)) {
                    cloneObj[key] = deepClone(obj[key], map)
                }
            }
            return cloneObj
        }

        // 实现myInstanceof
        const myInstanceOf = (left, right) => {
            let rightPrototype = right.prototype
            left = left.__proto__
            while (true) {
                if (left === null) return false
                if (left === rightPrototype) return true
                left = left.__proto__
            }
            return false
        }


        function foo() {
            var a = 10;
            return function (b) {
                a = a + b;
                return a
            }
        }
        function aaa() {
            var a = {
                b: 10,
            };
            return function (b) {
                a.b = a.b + b;
                return a
            }
        }
        let aa = aaa()
        let bb = foo()
        console.log(aa(10))
        console.log(aa(10))
        console.log(aa(10))
        console.log(bb(10))
        console.log(bb(10))
        console.log(bb(10))

    </script>
</body>

</html>